package com.electromagnetic.industry.software.manage.service.serviceimpl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.electromagnetic.industry.software.common.enums.EffectFlagEnum;
import com.electromagnetic.industry.software.common.enums.EleDataTypeEnum;
import com.electromagnetic.industry.software.common.exception.BizException;
import com.electromagnetic.industry.software.common.util.EleCommonUtil;
import com.electromagnetic.industry.software.common.util.UserThreadLocal;
import com.electromagnetic.industry.software.manage.mapper.EdFileInfoMapper;
import com.electromagnetic.industry.software.manage.mapper.EdFileRelationMapper;
import com.electromagnetic.industry.software.manage.pojo.models.EdFileInfo;
import com.electromagnetic.industry.software.manage.pojo.models.EdFileRelation;
import com.electromagnetic.industry.software.manage.pojo.models.Edge;
import com.electromagnetic.industry.software.manage.pojo.req.CheckNameUniqueRequest;
import com.electromagnetic.industry.software.manage.pojo.resp.FileRelationViewVO;
import com.electromagnetic.industry.software.manage.pojo.resp.FileSimpleInfoVO;
import com.electromagnetic.industry.software.manage.service.EdFileRelationService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

import static com.electromagnetic.industry.software.common.cons.ElectromagneticConstants.NAME_VALID_MSG;

@Service
public class EdFileRelationServiceImpl extends ServiceImpl<EdFileRelationMapper, EdFileRelation> implements EdFileRelationService {

    @Resource
    EdFileInfoMapper edFileInfoMapper;

    /**
     * 创建文件关系
     *
     * @param edFileRelation
     * @return
     */
    @Override
    @Transactional
    public Boolean createRelation(EdFileRelation edFileRelation) throws BizException {
        // 无法建立已建立的关系
        String queryId1 = edFileRelation.getId1();
        String queryId2 = edFileRelation.getId2();

        if (isFolder(queryId1) || isFolder(queryId2)) {
            throw new BizException("文件夹无法建立关系");
        }

        LambdaQueryWrapper<EdFileRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EdFileRelation::getId1, queryId1).eq(EdFileRelation::getId2, queryId2)
                .or()
                .eq(EdFileRelation::getId1, queryId2).eq(EdFileRelation::getId2, queryId1);
        EdFileRelation relation = this.getOne(queryWrapper);
        if (relation != null && relation.getEffectFlag().equals(EffectFlagEnum.EFFECT.code)) {
            throw new BizException("请勿重复建立关系");
        }

        boolean isSaved;
        if (relation != null) {
            relation.setRelationship(edFileRelation.getRelationship());
            relation.setEffectFlag(EffectFlagEnum.EFFECT.code);
            isSaved = this.updateById(relation);
        } else {
            EdFileRelation newRelation = new EdFileRelation();
            newRelation.newInit();
            BeanUtils.copyProperties(edFileRelation, newRelation);
            isSaved = this.save(newRelation);
        }
        if (isSaved) {
            UserThreadLocal.setSuccessInfo("", edFileRelation.getId(), StrFormatter.format("关联了文件"));
        }
        return isSaved;
    }

    /**
     * 取消文件关系
     *
     * @param id
     * @return
     */
    @Override
    public Boolean cancelRelation(String id) {

        EdFileRelation edFileRelation = this.getById(id);
        if (edFileRelation == null) {
            throw new BizException("关系不存在");
        }
        if (edFileRelation.getEffectFlag().equals(EffectFlagEnum.NOT_EFFECTIVE.code)) {
            throw new BizException("关系已取消");
        }
        edFileRelation.setEffectFlag(EffectFlagEnum.NOT_EFFECTIVE.code);
        boolean isRemoved = this.updateById(edFileRelation);
        if (isRemoved) {
            UserThreadLocal.setSuccessInfo("", id, StrFormatter.format("取消了文件关联"));
        }
        return isRemoved;
    }

    /**
     * 获取关系数据
     */
    @Override
    @Transactional
    public FileRelationViewVO listRelations(String startId) {

        FileRelationViewVO fileRelationViewVO = new FileRelationViewVO();

        List<Edge> visitedEdges = new ArrayList<>();
        Set<String> visitedIds = new HashSet<>();
        Set<String> uniqueRelationIds = new HashSet<>();

        Queue<String> queue = new LinkedList<>();

        // 初始化 BFS
        queue.add(startId);
        visitedIds.add(startId);

        while (!queue.isEmpty()) {
            String currentId = queue.poll();
            List<Edge> neighbors = getEdges(currentId);

            for (Edge edge : neighbors) {

                // 添加边信息
                if (!uniqueRelationIds.contains(edge.getRelationId())) {
                    visitedEdges.add(edge);
                    uniqueRelationIds.add(edge.getRelationId());
                }
                // 如果目标节点未访问，记录边并继续搜索
                if (!visitedIds.contains(edge.getTarget())) {
                    visitedIds.add(edge.getTarget()); // 标记目标节点为已访问
                    queue.add(edge.getTarget());
                }
            }
        }
        fileRelationViewVO.setEdges(visitedEdges);
        List<FileSimpleInfoVO> nodes = new ArrayList<>();
        for (String id : visitedIds) {
            FileSimpleInfoVO fileSimpleInfoVO = new FileSimpleInfoVO();
            EdFileInfo fileInfo = edFileInfoMapper.selectById(id);
            BeanUtils.copyProperties(fileInfo, fileSimpleInfoVO);
            nodes.add(fileSimpleInfoVO);
        }
        fileRelationViewVO.setNodes(nodes);
        EdFileInfo fileInfo = edFileInfoMapper.selectById(startId);
        UserThreadLocal.setSuccessInfo(Optional.ofNullable(fileInfo).map(EdFileInfo::getId).orElse(""), startId, StrFormatter.format("查询了文件{}的关联关系", startId));
        return fileRelationViewVO;
    }

    /**
     * 检查文件名是否唯一
     *
     * @return
     */
    @Override
    @Transactional
    public Boolean checkNameExist(CheckNameUniqueRequest checkNameUniqueRequest) {

        String mainName = checkNameUniqueRequest.getFileName();
        String suffix = checkNameUniqueRequest.getFileType();
        String parentId = checkNameUniqueRequest.getParentId();

        EdFileInfo newEdFileInfo = new EdFileInfo();
        newEdFileInfo.newInit();
        // 首先检查是否是同名文件
        Assert.isTrue(EleCommonUtil.isFileNameValid(mainName + "." + suffix), NAME_VALID_MSG);
        long count = edFileInfoMapper.selectCount(Wrappers.lambdaQuery(EdFileInfo.class)
                .eq(EdFileInfo::getParentId, parentId)
                .eq(EdFileInfo::getFileName, mainName)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .eq(EdFileInfo::getFileType, suffix));
        return count > 0;
    }

    /**
     * 逻辑删除文件关系
     *
     * @param fileId 文件主键id
     * @return
     */
    @Override
    public boolean logicRemove(String fileId) {
        Assert.notNull(fileId, "参数不能为空");
        return this.update(new LambdaUpdateWrapper<EdFileRelation>()
                .set(EdFileRelation::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code)
                .and(wrapper -> wrapper
                        .eq(EdFileRelation::getId1, fileId)
                        .or()
                        .eq(EdFileRelation::getId2, fileId))
                .eq(EdFileRelation::getEffectFlag, EffectFlagEnum.EFFECT.code));
    }

    private List<Edge> getEdges(String id) {

        LambdaQueryWrapper<EdFileRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EdFileRelation::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .and(wrapper -> wrapper.eq(EdFileRelation::getId1, id)
                        .or()
                        .eq(EdFileRelation::getId2, id));

        List<EdFileRelation> list = this.list(queryWrapper);
        List<Edge> edges = new ArrayList<>();
        for (EdFileRelation edFileRelation : list) {
            if (edFileRelation.getId1().equals(id)) {
                edges.add(new Edge(edFileRelation.getId1(), edFileRelation.getId2(), edFileRelation.getId(), edFileRelation.getRelationship()));
            } else {
                edges.add(new Edge(edFileRelation.getId2(), edFileRelation.getId1(), edFileRelation.getId(), edFileRelation.getRelationship()));
            }
        }
        return edges;
    }

    private boolean isFolder(String id) {
        EdFileInfo fileInfo = edFileInfoMapper.selectById(id);
        Assert.notNull(fileInfo, StrFormatter.format("文件不存在，ID为{}", id));
        return fileInfo.getDataType().equals(EleDataTypeEnum.FOLDER.code);
    }
}






